// --------------------------------------------------------------------------------------------------------------------
// <copyright file="DataManager.cs" company="">
//   
// </copyright>
// <summary>
//   Defines the DataManager type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Directory2Rss.Data
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;

    /// <summary>
    /// Datamanager Class
    /// </summary>
    public class DataManager
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="DataManager"/> class.
        /// </summary>
        public DataManager()
        {
            this.FolderGroups = GetFolderGroups();
        }

        /// <summary>
        /// Gets FolderGroups.
        /// </summary>
        public List<Types.FolderGroup> FolderGroups { get; private set; }

        /// <summary>
        /// Fill in the list containing all the FolderGroups
        /// </summary>
        /// <returns>
        /// A list of FolderGroups
        /// </returns>
        public static List<Types.FolderGroup> GetFolderGroups()
        {
            // Initialize instances of required data connectsions with the built connectionString
            Dir2RssLinq2Entities fileDataEntities = new Dir2RssLinq2Entities(SettingsManager.EntityConnectionString);

            // Query which returns all the Folder Groups to Iterate through
            List<Types.FolderGroup> folderGroups = (from folderGroup in fileDataEntities.vFolderGroupSet
                                                    select new Types.FolderGroup
                                                    {
                                                        FolderGroupSk = folderGroup.FolderGroupSk,
                                                        FolderGroupName = folderGroup.FolderGroupName,
                                                        FolderGroupScanFolder = folderGroup.FolderGroupScanFolder
                                                    }).ToList();

            return folderGroups;
        }

        /// <summary>
        /// Queries the database for a full list of files
        /// </summary>
        /// <param name="folderGroupSk">
        /// The folder Group Sk.
        /// </param>
        /// <returns>
        /// A list containing all the files from the database
        /// </returns>
        public List<Types.Files> GetDbFiles(int folderGroupSk)
        {
            // Initialize instances of required data connectsions with the built connectionString
            Dir2RssLinq2Entities fileDataEntities = new Dir2RssLinq2Entities(SettingsManager.EntityConnectionString);

            // Query which returns all the Folder Groups to Iterate through
            List<Types.Files> filesList = (from files in fileDataEntities.FilesSet
                                           where files.FileGroup.FolderGroup.FolderGroupSk == folderGroupSk
                                                    select new Types.Files
                                                    {
                                                        FileSk = files.FileSk,
                                                        FilePath = files.FilePath,
                                                        FileName = files.FileName
                                                    }).ToList();

            return filesList;
        }
        
        /// <summary>
        /// Compare filesDbQuery with fileSysList and populate a dataset with new files
        /// </summary>
        /// <param name="fileSysFiles">
        /// The file Sys Files.
        /// </param>
        /// <param name="databaseFiles">
        /// The database Files.
        /// </param>
        /// <returns>
        /// A list of new files in the scanned folders
        /// </returns>
        public List<Types.Files> GetNewFiles(List<Types.Files> fileSysFiles, List<Types.Files> databaseFiles)
        {
            // Compare Database with FileSystem and check for NEW files
            List<Types.Files> fileSysDbCompareNew = (from fileSysLine in fileSysFiles
                                                     join filesDbLine in databaseFiles on

                                                         // Force the comparison datatypes to Anonymous for behind the scenes c# magic
                                                         new { fileSysLine.FileName, fileSysLine.FilePath }
                                                         equals
                                                         new { filesDbLine.FileName, filesDbLine.FilePath }

                                                         // The two lines that really create the Outer join
                                                         into outer
                                                     from filesDbLine in outer.DefaultIfEmpty()

                                                     // Filter on only new rows from the filesystem
                                                     where filesDbLine == null
                                                     select new Types.Files
                                                                {
                                                                    FilePath = fileSysLine.FilePath,
                                                                    FileName = fileSysLine.FileName,
                                                                }).ToList();
                return fileSysDbCompareNew;
        }

        /// <summary>
        /// Create the FileGroup reference and return the Sk key
        /// </summary>
        /// <param name="folderGroupSk">
        /// The folder group sk.
        /// </param>
        /// <returns>
        /// The FileGroupSk key
        /// </returns>
        public EntityKey CreateFileGroup(int folderGroupSk)
        {
            // Initialize instances of required data connectsions with the built connectionString
            Dir2RssLinq2Entities fileDataEntities = new Dir2RssLinq2Entities(SettingsManager.EntityConnectionString);

            // Create and populate the Foreign key used for insertion into the Files table
            var folderGroupSkKey = new EntityKey("Dir2RssLinq2Entities.FolderGroupSet", "FolderGroupSk", folderGroupSk);

            // Create GUID
            Guid fileGroupGuid = Guid.NewGuid();

            // Insert into FileGroup a new 
            FileGroup filegroup = new FileGroup
                                      {
                                          FolderGroupReference = { EntityKey = folderGroupSkKey },
                                          FileGroupAdded = SettingsManager.FileGroupAdded,
                                          FileGroupGuid = fileGroupGuid
                                      };

            fileDataEntities.AddToFileGroupSet(filegroup);
            fileDataEntities.SaveChanges();

            var fileGroupSkLast = (from fg in fileDataEntities.FileGroupSet
                                   where fg.FileGroupAdded == SettingsManager.FileGroupAdded && fg.FileGroupGuid == fileGroupGuid
                                   select fg.FileGroupSk).First();

            // Create and populate the Foreign key used for insertion into the Files table
            var fileGroupSkKey = new EntityKey("Dir2RssLinq2Entities.FileGroupSet", "FileGroupSk", fileGroupSkLast);

            return fileGroupSkKey;
        }

        /// <summary>
        /// Writes new files to database
        /// </summary>
        /// <param name="fileGroupSkKey">
        /// The file Group Sk Key.
        /// </param>
        /// <param name="filesToWrite">
        /// The files to write.
        /// </param>
        /// <returns>
        /// A counter of how many lines were written to the database
        /// </returns>
        public int WriteNewFiles(EntityKey fileGroupSkKey, List<Types.Files> filesToWrite)
        {
            // Initialize instances of required data connectsions with the built connectionString
            Dir2RssLinq2Entities fileDataEntities = new Dir2RssLinq2Entities(SettingsManager.EntityConnectionString);

            // Initialize the counter
            int counter = 0;

            foreach (var line in filesToWrite)
            {
                // Initialize new Files table for writing
                Files files = new Files
                {
                    FileGroupReference = { EntityKey = fileGroupSkKey },
                    FilePath = line.FilePath,
                    FileName = line.FileName
                };

                // Map the Source to Destination columns
                fileDataEntities.AddToFilesSet(files);

                // Increment the counter
                counter += 1;
            }

            // Commit changes to Database
            fileDataEntities.SaveChanges();

            return counter;
        }

        /// <summary>
        /// Compare filesDbQuery with fileSysList and populate a dataset with deleted files
        /// </summary>
        /// <param name="fileSysFiles">
        /// The file Sys Files.
        /// </param>
        /// <param name="databaseFiles">
        /// The database Files.
        /// </param>
        /// <returns>
        /// A list of deleted files from the database
        /// </returns>
        public List<Types.Files> GetMissingFiles(List<Types.Files> fileSysFiles, List<Types.Files> databaseFiles)
        {
            // Compare filesDbQuery with fileSysList
            List<Types.Files> fileSysDbCompareDelete = (from filesDbLine in databaseFiles
                                                         join fileSysLine in fileSysFiles on

                                                             // Force the comparison datatypes to Anonymous for behind the scenes c# magic
                                                             new { filesDbLine.FileName, filesDbLine.FilePath }
                                                             equals
                                                             new { fileSysLine.FileName, fileSysLine.FilePath }

                                                             // The two lines that really create the Outer join
                                                             into outer
                                                         from fileSysLine in outer.DefaultIfEmpty()

                                                         // Filter on only new rows from the filesystem
                                                         where fileSysLine == null
                                                         select new Types.Files
                                                                    {
                                                                        FileSk = filesDbLine.FileSk
                                                                    }).ToList();
            return fileSysDbCompareDelete;
        }

        /// <summary>
        /// Deletes missing files
        /// </summary>
        /// <param name="filesSkToDelete">
        /// The files Sk To Delete.
        /// </param>
        /// <returns>
        /// A counter of how many rows were returned
        /// </returns>
        public int DeleteMissingFiles(List<Types.Files> filesSkToDelete)
        {
            // Initialize instances of required data connectsions with the built connectionString
            Dir2RssLinq2Entities fileDataEntities = new Dir2RssLinq2Entities(SettingsManager.EntityConnectionString);

            // Initialize the counter
            int counter = 0;

            // Delete the rows from the Files table
            foreach (var fileSkToDelete in filesSkToDelete)
            {
                // Create and instance of the table and set the target value to be Deleted
                Files file = new Files { FileSk = fileSkToDelete.FileSk };

                // Attach the current FileSk value to the table
                fileDataEntities.AttachTo("FilesSet", file);

                // Delete the attached value from the table
                fileDataEntities.DeleteObject(file);

                // Increment the counter
                counter += 1;
            }

            // Commit the Deletions to the database
            fileDataEntities.SaveChanges();

            return counter;
        }

        /// <summary>
        /// Creates the RSS XML
        /// </summary>
        /// <param name="folderGroupSk">
        /// The folder group sk.
        /// </param>
        /// <returns>
        /// Return the RSS XML for the specified FolderGroupSk
        /// </returns>
        public string GetRssXmlOutput(int folderGroupSk)
        {
            // Initialize instances of required data connectsions with the built connectionString
            Dir2RssLinq2Sql dir2RssLinq2Sql = new Dir2RssLinq2Sql(SettingsManager.SqlConnectionString);

            // Query for the XML Result set and return it
            var xmlResults = from x in dir2RssLinq2Sql.uspGetRssXml(folderGroupSk)
                             select x;

            string xmlResult = string.Empty;

            foreach (uspGetRssXmlResult result in xmlResults)
            {
                xmlResult = result.RssXmlOutput;
            }
            
            return xmlResult;
        }
    }
}